#include "../TcpServer.h"
#include "../Acceptor.h"
#include "../EventLoop.h"
#include "../EventLoopThreadPool.h"
using namespace yhaida;
TcpServer::TcpServer(EventLoop *loop, const InetAddress &listenAddr,Option option)
    : _start(false),
      _nextConnId(1),
      _name(listenAddr.toHostPort()),
      _mainEventLoop(CHECK_NOTNULL(loop)),
      _acceptor(new Acceptor(loop, listenAddr,option == kReusePort)),
      _threadPool(new EventLoopThreadPool(loop))
{
    _acceptor->setNewConnectionCallback(
        std::bind(&TcpServer::newConnection, this, _1, _2));
}
TcpServer::~TcpServer()
{
}
void TcpServer::setThreadNum(int numThreads)
{
    assert(numThreads >= 0);
    _threadPool->setThreadNum(numThreads);
}
void TcpServer::start()
{
    assert(!_start);
    _start = true;

    _threadPool->start(_threadInitCallback);

    if (!_acceptor->listenning())
    {
        // get_pointer->std::unique_ptr<T>::get();
        _mainEventLoop->runInLoop(
            std::bind(&Acceptor::listen, get_pointer(_acceptor)));
    }
}
//当listen 新的连接建立_acceptor->handleRead()即在构造函数里面回调了newConnection()
//这里sockfd就是新得到的connfd，InetAddress就是新得到的connfd的IP与Port.
void TcpServer::newConnection(int sockfd, const InetAddress &addr)
{
    //处理_connections   --        Map
    _mainEventLoop->assertInLoopThread();
    char buff[32];
    snprintf(buff, sizeof(buff), "#%d", _nextConnId);
    ++_nextConnId;
    std::string connName = _name + buff;

    LOG_INFO << "TcpServer::newConnection [" << _name
             << "] - new connection [" << connName
             << "] from " << addr.toHostPort();

    InetAddress localAddr(sockets::getLocalAddr(sockfd));
    //对于服务器来说，在bind以后就可以调用getsockname
    //来获取本地地址和端口，虽然这没有什么太多的意义。

    // getpeername->相当于accept之后得到的地址
    // getpeername只有在链接建立以后才调用，否则不能正确获得对方地址和端口，
    //所以他的参数描述字一般是链接描述字而非监听 套接口描述字。

    EventLoop *ioLoop = _threadPool->getNextLoop(); //经过轮询得到一个空闲的EventLoop
    TcpConnectionPtr conn(
        new TcpConnection(ioLoop, connName, sockfd, localAddr, addr));

    _connections[connName] = conn;

    conn->setConnectionCallback(_connectionCallback);
    conn->setMessageCallback(_messageCallback);
    conn->setWriteCompleteCallback(_writeCompleteCallback);
    conn->setCloseCallback(std::bind(&TcpServer::removeConnection, this, _1));

    // conn->connectEstablished(); //这步完成了TcpConnectionPtr conn的注册
    // 在对应得IO线程中将connfd注册
    ioLoop->runInLoop(std::bind(&TcpConnection::connectEstablished, conn));
}

void TcpServer::removeConnection(const TcpConnectionPtr &conn)
{
    // unsafe 可能同时有多个connfd关闭
    _mainEventLoop->runInLoop(std::bind(&TcpServer::removeConnectionInLoop, this, conn));
}

void TcpServer::removeConnectionInLoop(const TcpConnectionPtr &conn)
{
    _mainEventLoop->assertInLoopThread();
    LOG_INFO << "TcpServer::removeConnectionInLoop [" << _name
             << "] - connection " << conn->name();
    //删除TcpServer中Map的那部分
    size_t n = _connections.erase(conn->name());
    assert(n == 1);
    //只是避免程序中未使用的变量在编译时出现警告
    (void)n;
    EventLoop *ioLoop = conn->getLoop();
    //确保TcpConnection的销毁一定是在EventLoop中channel全部遍历完,queueInLoop回调完成的时候
    ioLoop->queueInLoop(std::bind(&TcpConnection::connectDestroyed, conn));
}